package controller;

import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import model.Extra;
import model.KISpieler;
import model.Spieler;
import model.Spielfeld;
import view.MainFrame;

public class Spiel implements KeyListener {
	public Spielfeld spielfeld;
	public Logik logik;
	private Spieler[] spieler;
	public MainFrame frame;
	public int time;
	private boolean wait = true;
	private boolean paused = false;
	public ArrayList<Extra> extras;

	private ScheduledThreadPoolExecutor threadPool;

	public static int GAME_WIDTH = 900;
	public static int GAME_HEIGHT = 850;
	public static final int LUECKE_LENGTH = 3;
	public static final int FPS = 30;

	public static Spiel CURRENT_SPIEL = null;

	public Spiel(Spieler[] spieler, Logik logik, MainFrame frame) {
		this.spieler = spieler;
		this.logik = logik;
		this.frame = frame;

		frame.getGamePanel().addKeyListener(this);
	}

	public void start() {
		CURRENT_SPIEL = this;

		GAME_WIDTH = frame.getContentPane().getWidth();
		GAME_HEIGHT = frame.getContentPane().getHeight();

		spielfeld = new Spielfeld(GAME_WIDTH, GAME_HEIGHT);
		frame.getGamePanel().setSpielfeld(spielfeld);
		frame.getGamePanel().setSpieler(spieler);
		frame.getGamePanel().setBackground(Color.BLACK);

		logik.verteileSpieler(spielfeld, spieler);
		frame.repaint();

		threadPool = new ScheduledThreadPoolExecutor(1);
		time = -FPS * 4 + 1;
		paused = false;

		this.frame.infoPanel.setSpieler(spieler);

		final Runnable paintRunnable = new Runnable() {

			@Override
			public void run() {
				frame.gamePanel.repaintDirtyRegions();
				frame.repaint();
			}
		};

		threadPool.scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				time++;
				if (time < 0) {
					// Vor dem Start Countdown anzeigen
					int secsLeft = -time / FPS;
					frame.gamePanel.setInfoString(secsLeft == 0 ? "Go!"
							: secsLeft + "");
					frame.repaint();
				} else {
					if (paused) {
						// Pause: Pause anzeigen
						frame.gamePanel.setInfoString("Pause");
						frame.repaint();
					} else {
						frame.gamePanel.setInfoString("");
						logik.prepareStep();

						for (Spieler s : spieler) {
							if (s instanceof KISpieler) {
								((KISpieler) s).decideAction(spielfeld);
							}
						}
						// Schritt machen
						for (int i = 0; i < spieler.length; i++) {
							logik.moveSpieler(spielfeld, spieler[i]);
							frame.gamePanel.addDirtyRegion(spieler[i]
									.getLinie().lastSchritt.getBoundingRect());
						}
					}
				}

				threadPool.schedule(paintRunnable, 0, TimeUnit.NANOSECONDS);
			}
		}, 0, 1000 / FPS, TimeUnit.MILLISECONDS);
	}

	public int getTime() {
		return time;
	}

	public Spieler[] getSpieler() {
		return spieler;
	}

	@Override
	public void keyPressed(KeyEvent e) {
		char c = Character.toLowerCase(e.getKeyChar());

		for (int i = 0; i < spieler.length; i++) {
			if (spieler[i].getLeftKey() == c)
				logik.spielerNachLinks(spieler[i]);
			if (spieler[i].getRightKey() == c)
				logik.spielerNachRechts(spieler[i]);
		}
		if (System.currentTimeMillis() - e.getWhen() > 100)
			System.out.println(System.currentTimeMillis() - e.getWhen() + "ms");
	}

	@Override
	public void keyReleased(KeyEvent e) {
		char c = Character.toLowerCase(e.getKeyChar());

		if (c == ' ' && wait) {
			wait = false;
			start();
		} else if (c == ' ') {
			paused = !paused;
		}

		for (int i = 0; i < spieler.length; i++) {
			if (spieler[i].getLeftKey() == c)
				logik.spielerStopptNachLinks(spieler[i]);
			if (spieler[i].getRightKey() == c)
				logik.spielerStopptNachRechts(spieler[i]);
		}
	}

	@Override
	public void keyTyped(KeyEvent e) {
	}

	public void stopRunde() {
		if (threadPool != null) {
			threadPool.shutdownNow();
			threadPool = null;
		}
	}

	public void pause() {
		paused = true;
	}

	public void setAwaitRunde(boolean b) {
		this.wait = b;
	}

	public void updatePunkte() {
		this.frame.infoPanel.updatePunkte();
	}
}
